﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net;
using System.Text;
using System.Threading;
using System.Xml.Linq;
using System.Xml.XPath;

namespace Shoozla.DataModel
{

    // The Idea is to magically find the right TAGS listening the file
    // the api used seems not working, it just uploads the file and analyze it but doesn't recognize the real song
    // it returns the orginal tags information
    // in the website they states that I should call another API, passing the "hashcode" calculated from the song.
    // need an Encoder/Decoder because is Mp3

    // project stopped right now (future expansion)
    

    public class EchonestTagsSearcher : TagsSearcher
    {
        private const String APIKEY = "CZIJVGSCAKVOL4Q2C";

        /// <summary>
        /// Compression factor, determines the number of bytes (sec) to send for analysis
        /// use only integer number (used to divide the total length)
        /// </summary>
        public int XFactor { get; set; }

        public EchonestTagsSearcher(CancellationTokenSource cancelTokenSource, StatisticsLogger stats):base(cancelTokenSource,stats)
        {
            XFactor = 15;
        }

        protected override void SetAddInInformation()
        {
            AddInName = "Echonest Tags Searcher";
            AddInDescription = "Uses Echonest servers to guess the song";
        }

        #region Find methods
        /// <summary>
        /// Find the Artist, Song, Album, ImageUrl tags of a song
        /// </summary>
        /// <returns>true if match found</returns>
        public override bool FindTagsInternal(Mp3File unknownSong)
        {
            bool found = false;
            byte[] sample = File.ReadAllBytes(unknownSong.FileName.FullName);
            byte[] short_sample = new byte[sample.Length / XFactor];

            //create a small sample, only first X seconds
            for (int i = 0; i < sample.Length / XFactor; i++)
                short_sample[i] = sample[i];

            sample = null;
            //Trace.WriteLine("sample size: " + short_sample.Length / 1024 + " KB");
            var mp3 = AnalyzeSample(short_sample);
            if (mp3 != null)
            {
                //copy back to the original file
                Mp3File.CloneMp3(mp3, ref unknownSong);
                found = true;
            }
            short_sample = null;
            return found;

        }

        private Mp3File AnalyzeSample(byte[] mp3sample)
        {
            Mp3File mp3 = null;

            try
            {
                WebClient client = new WebClient();
                string uploadAddress = "http://developer.echonest.com/api/v4/track/upload?api_key=" + APIKEY + "&wait=true&bucket=audio_summary&filetype=mp3&format=xml";
                client.BaseAddress = uploadAddress;
                client.Headers.Add("Content-Type", "application/octet-stream");
                byte[] responseArray = client.UploadData(uploadAddress, "POST", mp3sample);
                using (var stream = new MemoryStream(responseArray, false))
                {
                    var doc = XDocument.Load(stream);
                    XPathNavigator nav = doc.CreateNavigator();
                    XPathNodeIterator it = nav.Select("//track");
                    while (it.MoveNext())
                    {
                        mp3 = new Mp3File();
                        mp3.Artist = it.Current.SelectSingleNode("artist").Value;
                        mp3.Title = it.Current.SelectSingleNode("title").Value;
                        mp3.AlbumName = it.Current.SelectSingleNode("release").Value;
                        Uri albumUri = RetrieveAlbumUri(it.Current.SelectSingleNode("id").Value);
                        if (albumUri != null)
                            mp3.ImageUrl = albumUri;
                        break;
                    }
                }
            }
            catch (Exception e)
            {
                Trace.WriteLine(String.Format("[ERROR] EchoNestClient: AnalyzeSample: {0}", e.Message));
                mp3 = null; //not found or error
            }

            return mp3;
        }

        private Uri RetrieveAlbumUri(String trackID)
        {

            try
            {
                WebClient client = new WebClient();
                string searchAddress = "http://developer.echonest.com/api/v4/track/profile?api_key=" + APIKEY + "&id=" + trackID + "&bucket=audio_summary&format=xml";
                client.Headers.Add("Content-Type", "multipart/form-data");
                byte[] responseArray = client.DownloadData(searchAddress);
                using (var stream = new MemoryStream(responseArray, false))
                {
                    var doc = XDocument.Load(stream);
                    XPathNavigator nav = doc.CreateNavigator();
                    XPathNodeIterator it = nav.Select("//track");
                    while (it.MoveNext())
                    {
                        var node = it.Current.SelectSingleNode("release_image");
                        if (node == null)
                            break; //no release_image (album)

                        string uripath = node.Value;
                        if (uripath != null)
                            return new Uri(uripath);
                    }
                }

            }
            catch (WebException we)
            {
                Trace.WriteLine(String.Format("[ERROR] EchoNestClient: RetrieveAlbumUri: {0}", we.Message));
            }

            return null;
        }
        #endregion
    }
}
